<script lang="ts">
export default {
  name: 'Study5StuDemo2'
}
</script>

<template>
  <h2>侦听数据源类型</h2>
  <div class="note">
    <p>watch 的第一个参数可以是不同形式的“数据源",如</p>
    <p>(1) 一个ref(包括计算属性，计算属性返回的是ref对象)</p>
    <p>(2) 一个响应式对象</p>
    <p>(3) 一个getter函数</p>
    <p>(4) 多个数据源组成的数组</p>
  </div>
  <div class="note">
    <p>注意事项</p>
    <p>(1) 不能直接侦听”响应式对象“的属性值（可以使用getter侦听）</p>
  </div>
  <div class="note">
    <p>watch的第三个参数（可选）</p>
    <p>(1) deep选项：用于强制转换侦听器，true转化深层侦听器，false转化浅层侦听器（默认情况下deep值为true）</p>
    <p>(2) immediate选项：用于在监听数据改变之前先触发一次（即时回调的侦听器）</p>
    <p>(3) once选项：只触发一次（一次性侦听器）</p>
    <p>(4) 注意：once 会把 immediate 触发的一次变化消费掉，once和immediate在一起使用没意义</p>
  </div>

  <hr class="hr-style" />
  <div class="test">
    inputVal:
    <input type="text" v-model="inputVal" />
  </div>
  <div class="test">
    <label for="">num1:</label>
    <input type="number" v-model="num1" />
    <label for="">num2:</label>
    <input type="number" v-model="num2" />
    <div>求和：{{ sumNum }}</div>
  </div>

  <hr class="hr-style" />
  <div class="test">
    <input type="text" v-model="reacUser.name" />
  </div>
</template>

<script setup lang="ts">
import { computed, reactive, ref, watch } from 'vue'

const inputVal = ref('默认值')
const num1 = ref(0)
const num2 = ref(0)

const sumNum = computed(() => num1.value + num2.value)

const reacUser = reactive({
  name: '站起来',
  sex: '男',
  love: {
    lanqiu: '喜欢'
  }
})

// 监听计算属性
// 1. 传入一个ref对象
watch(inputVal, (newVal, oldVal) => {
  console.log(newVal, 'ref: newVal')
  console.log(oldVal, 'ref: oldVal')
})

watch(sumNum, (newVal, oldVal) => {
  console.log(newVal, 'computed: newVal')
  console.log(oldVal, 'computed: oldVal')
})

// 2. 传入一个响应式对象
// 直接给 watch() 传入一个响应式对象，会`隐式地创建一个深层侦听器`——该回调函数在所有嵌套的变更时都会被触发：
watch(reacUser, (newVal, oldVal) => {
  console.log(newVal, '`响应式对象`:newVal')
  console.log(oldVal, '`响应式对象`:oldVal')
})

// 3.传入一个getter 函数
watch(
  () => num1.value * num2.value,
  (newVal, oldVal) => {
    console.log('num1.value*num2.value')
    console.log(newVal, 'getter:newVal')
    console.log(oldVal, 'getter:oldVal')
  }
)

// 4. 多个数据源组成的数组
watch(
  [inputVal, () => inputVal.value, () => num1.value * num2.value, () => num1.value + num2.value],
  ([val1, val2, val3, val4]) => {
    console.log(val1, 'arr1:newVal')
    console.log(val2, 'arr2:newVal')
    console.log(val3, 'arr3:newVal')
    console.log(val4, 'arr4:newVal')
  }
)

// 注意：不能直接侦听"响应式对象"的属性值
// 错误示范:没有与此调用匹配的重载。最后一个重载给出了以下错误。类型“string”的参数不能赋给类型“object”的参数
// watch(reaUser.love.lanqiu,(newVal,oldVal)=>{
//   console.log(newVal);
//   console.log(oldVal);
// })

// 可以使用getter侦听"响应式对象"的属性值
watch(
  () => reacUser.name,
  (newVal, oldVal) => {
    console.log(newVal, '`响应式对象`的属性值:newVal')
    console.log(oldVal, '`响应式对象`的属性值:oldVal')
  }
)

// 显式地加上 deep 选项，强制转成深层侦听器：(默认深层侦听器)
watch(
  reacUser,
  (newVal, oldVal) => {
    console.log(newVal, '`响应式对象-强制转成深层侦听器`:newVal')
    console.log(oldVal, '`响应式对象-强制转成深层侦听器`:oldVal')
  },
  {
    deep: true
  }
)

// 显式地加上 deep 选项，强制转成浅层侦听器：
watch(
  reacUser,
  (newVal, oldVal) => {
    console.log(newVal, '`响应式对象-强制转成浅层侦听器`:newVal')
    console.log(oldVal, '`响应式对象-强制转成浅层侦听器`:oldVal')
  },
  {
    deep: false
  }
)

// 即时回调的侦听器
// 在监听数据改变之前，先触发一次
watch(
  inputVal,
  (newVal, oldVal) => {
    console.log(newVal, 'ref:newVal')
    console.log(oldVal, 'ref:oldVal')
  },
  {
    // 先触发一次
    immediate: true
  }
)

// 一次性侦听器
watch(
  inputVal,
  (newVal, oldVal) => {
    console.log('一次性侦听器')

    console.log(newVal, 'ref:newVal')
    console.log(oldVal, 'ref:oldVal')
  },
  {
    // 先触发一次
    // immediate: true,
    //once和immediate共同使用请注意， once 会把 immediate 触发的一次变化消费掉，once和immediate在一起使用每意义
    once: true
  }
)
</script>

<style scoped>
body {
  padding: 20px;
}
h2 {
  color: red;
}
h3 {
  color: rgb(220, 85, 85);
}
h4 {
  color: skyblue;
}
.hr-style {
  border: 3px solid gold;
  margin: 20px 0;
}
.note {
  margin: 10px;
  padding: 10px;
  border: 3px solid rgb(221, 121, 202);
}
.note p {
  color: rgb(226, 106, 204);
  font-weight: bold;
}
</style>
